/**
 * Created by IntelliJ IDEA.
 * User: Slejus
 * Date: 13.7.16
 * Time: 08.50
 * To change this template use File | Settings | File Templates.
 */

// get param value from URL
/*function getURLParameters(paramName) {
    var sURL = window.document.URL.toString();
    if (sURL.indexOf("?") > 0) {
        var arrParams = sURL.split("?");
        var arrURLParams = arrParams[1].split("&");
        var arrParamNames = new Array(arrURLParams.length);
        var arrParamValues = new Array(arrURLParams.length);
        var i = 0;
        for (i = 0; i < arrURLParams.length; i++) {
            var sParam =  arrURLParams[i].split("=");
            arrParamNames[i] = sParam[0];
            if (sParam[1] != "") {
                arrParamValues[i] = decodeURIComponent(sParam[1]);
            } else {
                arrParamValues[i] = "No Value";
                return "error";
            }
        }
        for (i = 0; i < arrURLParams.length; i++) {
            if(arrParamNames[i] == paramName){
                return arrParamValues[i];
            }
        }
        return "error";
    }
}

var validateTaskSigning = function(res) {
    var response = eval('(' + res.serverResponse.responseText + ')');
    var status = response.data.properties.bpm_status;
    if (status) {
        console.log("Response is OK");
        if(status === "Signed") {
            console.log("Task is signed");
        } else {
            console.log("Task is not signed");
            return false;
        }
    } else {
        console.log("Response is BAD");
        return false;
    }
    return true;
};

function validateSigning(){
    var task = null;
    taskId = getURLParameters("taskId");
    if (taskId != "error"){
        Alfresco.util.Ajax.jsonGet({
            url : Alfresco.constants.PROXY_URI + "api/task-instances/"+encodeURIComponent(taskId),
            successCallback : {
                fn : validateTaskSigning,
                scope : this
            },
            failureCallback : {
                fn : function() {},
                scope : this
            }
        });
    }
} */
// Ensure Alfresco.forms and validation objects exist
Alfresco.forms = Alfresco.forms || {};
Alfresco.forms.validation = Alfresco.forms.validation || {};

/**
 * Class to represent the forms runtime.
 *
 * @namespace Alfresco.forms
 * @class Alfresco.forms.Form
 */
(function()
{
    /**
     * YUI Library aliases
     */
    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Selector = YAHOO.util.Selector,
        KeyListener = YAHOO.util.KeyListener;

    /**
     * Constructor for a form.
     *
     * @param {String} formId The HTML id of the form to be managed
     * @return {Alfresco.forms.Form} The new Form instance
     * @constructor
     */
    Alfresco.forms.Form = function(formId)
    {
        this.formId = formId;
        this.showSubmitStateDynamically = false;
        this.reusable = false;
        this.submitAsJSON = false;
        this.submitElements = [];
        this.validations = [];
        this.tooltips = {};
        this._valid = null;
        this._fieldEvents = {};
        this._visitedFields = {};
        this.ajaxSubmit = false;
        this.ajaxSubmitMethod = "POST";
        this.ajaxNoReloadOnAuthFailure = null;
        this.errorContainer = "tooltip";
        this.showMultipleErrors = false;

        // Make sure to hide error containers (i.e. tooltips) when overlays and panels are closed

        YAHOO.Bubbling.on("showPanel", this.hideErrorContainer, this);
        YAHOO.Bubbling.on("hidePanel", this.hideErrorContainer, this);
        YAHOO.Bubbling.on("showOverlay", this.hideErrorContainer, this);
        YAHOO.Bubbling.on("hideOverlay", this.hideErrorContainer, this);

        return this;
    };

    YAHOO.lang.augmentObject(Alfresco.forms.Form,
        {
            NOTIFICATION_LEVEL_NONE: 1,

            /**
             * Applies css classes against the fields
             */
            NOTIFICATION_LEVEL_FIELD: 2,

            /**
             * Invokes the error containers
             */
            NOTIFICATION_LEVEL_CONTAINER: 3
        });

    Alfresco.forms.Form.prototype =
    {

        /**
         * HTML id of the form being represented.
         *
         * @property formId
         * @type string
         */
        formId: null,

        /**
         * List of ids and/or elements being used to submit the form.
         *
         * @property submitElements
         * @type object[]
         */
        submitElements: null,

        /**
         * Flag to determine whether the submit elements dynamically update
         * their state depending on the current values in the form.
         *
         * @property showSubmitStateDynamically
         * @type boolean
         */
        showSubmitStateDynamically: null,

        /**
         * Flag to determine whether the submit elements shall be enabled again after a successful form submission.
         *
         * @property reusable
         * @type boolean
         * @default false
         */
        reusable: false,

        /**
         * Flag to determine whether the form will be submitted using an AJAX request.
         *
         * @property ajaxSubmit
         * @type boolean
         */
        ajaxSubmit: null,

        /**
         * String representing where errors should be displayed.
         * If the value is not "alert" it's presumed the string is the id of an
         * HTML object to be used as the error container.
         *
         * @property errorContainer
         * @type string
         */
        errorContainer: null,

        /**
         * Boolean deciding if on eor many errors shall be displayed at a time.
         *
         * @property showMultipleErrors
         * @type boolean
         */
        showMultipleErrors: false,

        /**
         * Object literal containing the abstract function for pre-submission form processing.
         *   fn: function, // The override function.
         *   obj: object, // An object to pass back to the function.
         *   scope: object // The object to use for the scope of the function.
         *
         * @property doBeforeFormSubmit
         * @type object
         */
        doBeforeFormSubmit:
        {
            fn: function(form, obj){},
            obj: null,
            scope: this
        },

        /**
         * Object literal containing the abstract function for intercepting AJAX form submission.
         * Returning false from the override will prevent the Forms Runtime from submitting the data.
         *   fn: function, // The override function.
         *   obj: object, // An object to pass back to the function.
         *   scope: object // The object to use for the scope of the function.
         *
         * @property doBeforeAjaxRequest
         * @type object
         */
        doBeforeAjaxRequest:
        {
            fn: function(form, obj)
            {
                return true;
            },
            obj: null,
            scope: this
        },

        /**
         * Object holding the callback handlers and messages for AJAX submissions.
         * The callback handlers are themselves an object of the form:
         *   fn: function, // The handler to call when the event fires.
         *   obj: object, // An object to pass back to the handler.
         *   scope: object // The object to use for the scope of the handler.
         *
         * @property ajaxSubmitHandlers
         * @type object
         */
        ajaxSubmitHandlers: null,

        /**
         * String representing the http method to be used for the
         * ajax call. Default is POST.
         *
         * @property ajaxSubmitMethod
         * @type String
         */
        ajaxSubmitMethod: null,

        /**
         * Decides if the browser shall try and reload the current page if a form submission fails due to auth failure.
         *
         * Possible values:
         * true - browser will NOT reload current page
         * false - browser will reload current page
         * null - Will use the default value of noReloadOnAuthFailure in Alfresco.util.Ajax.request
         *
         * @property ajaxNoReloadOnAuthFailure
         * @type String
         * @default null
         */
        ajaxNoReloadOnAuthFailure: null,

        /**
         * Flag to determine whether the form data should be submitted
         * represented by a JSON structure.
         *
         * @property submitAsJSON
         * @type boolean
         */
        submitAsJSON: null,

        /**
         * List of validations to execute when the form is submitted.
         *
         * @property validations
         * @type object[]
         */
        validations: null,

        /**
         * The tooltips used to display an error when errorContainer is set to "tooltip"
         *
         * @property tooltips
         * @type object
         */
        tooltips: null,

        /**
         * The fields and events that already have a listener attached to them.
         */
        _fieldEvents: {},

        _FIELD_EVENT_UNDEFINED: undefined,
        _FIELD_EVENT_LISTEN: 1,
        _FIELD_EVENT_VALIDATE: 2,

        /**
         * The fields that are considered to have been visited by the user.
         * Meaning that they will display balloon and red color if users tabs out of them.
         */
        _visitedFields: null,

        /**
         * Indicates if the field is valid, will be updated by _runValidations
         */
        _valid: null,

        /**
         * Sets up the required event handlers and prepares the form for use.
         * NOTE: This must be called after all other setup methods.
         *
         * @method init
         */
        init: function()
        {
            var form = Dom.get(this.formId);
            if (form !== null)
            {
                if (form.getAttribute("forms-runtime") != "listening")
                {
                    // add the event to the form and make the scope of the handler this form.
                    Event.addListener(form, "submit", this._submitInvoked, this, true);
                    form.setAttribute("forms-runtime", "listening");
                    if (this.ajaxSubmit)
                    {
                        form.setAttribute("onsubmit", "return false;");
                    }
                }

                // determine if the AJAX and JSON submission should be enabled
                if (form.getAttribute("enctype") && form.getAttribute("enctype") == "application/json")
                {
                    this.ajaxSubmit = true;
                    this.submitAsJSON = true;
                }

                // find the default submit elements if there are no submitIds set
                if (this.submitElements && this.submitElements.length == 0)
                {
                    // use a selector to find any submit elements for the form
                    var nodes = Selector.query('#' + this.formId + ' > input[type="submit"]');
                    for (var x = 0, xx = nodes.length; x < xx; x++)
                    {
                        var elem = nodes[x];
                        this.submitElements.push(elem.id);
                    }
                }

                // make sure the submit elements start in the correct state
                this._runValidations(null, null, Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD);

                // Set up an escape listener so we can close 3rd party widgets such as ballons when escape is clicked
                var escapeListener = new KeyListener(document,
                    {
                        keys: KeyListener.KEY.ESCAPE
                    },
                    {
                        fn: function(id, keyEvent)
                        {
                            for (var id in this.tooltips)
                            {
                                if (this.tooltips.hasOwnProperty(id))
                                {
                                    this.tooltips[id].hide();
                                }
                            }
                        },
                        scope: this,
                        correctScope: true
                    });
                escapeListener.enable();
            }
            else
            {
                this._showInternalError("form with id of '" + this.formId +
                    "' could not be located, ensure the form is created after the form element is available.");
            }
        },

        /**
         * If the form has been tested a boolean is returned to indicate if the form is valid.
         * If it hasn't been tested null is returned,
         *
         * @return {null|Boolean}
         */
        isValid: function()
        {
            return this._valid;
        },

        /**
         * Deprecated!
         *
         * All forms are always validated before submit
         *
         * Enables or disables validation when the form is submitted.
         *
         * @method setValidateOnSubmit
         * @param validate {boolean} true to validate on submission, false
         *        to avoid validation
         */
        setValidateOnSubmit: function(validate)
        {
        },

        /**
         * Deprecated!
         *
         * All fields are now always validated.
         *
         * Sets whether all fields are validated when the form is submitted.
         *
         * @method setValidateAllOnSubmit
         * @param validate {boolean} true to validate all fields on submission, false
         *        to stop after the first validation failure
         */
        setValidateAllOnSubmit: function(validateAll)
        {
        },

        /**
         * Sets the list of ids and/or elements being used to submit the form.
         * By default the forms runtime will look for and use the first
         * input field of type submit found in the form being managed.
         *
         * @method setSubmitElements
         * @param submitElements {object | object[]} Single object or array of objects
         */
        setSubmitElements: function(submitElements)
        {
            if (!YAHOO.lang.isArray(submitElements))
            {
                this.submitElements[0] = submitElements;
            }
            else
            {
                this.submitElements = submitElements;
            }
        },

        /**
         * Sets the container where errors will be displayed.
         *
         * @method setErrorContainer
         * @param container {string} String representing where errors should
         *        be displayed. If the value is not "alert" it's presumed the
         *        string is the id of an HTML object to be used as the error
         *        container
         */
        setErrorContainer: function(container)
        {
            this.errorContainer = container;
        },

        /**
         * Dictates if the containers will display one or many errors at a time.
         *
         * @method setShowMultipleErrors
         * @param showMultipleErrors {boolean} Set to true to display multiple errors
         */
        setShowMultipleErrors: function(showMultipleErrors)
        {
            this.showMultipleErrors = showMultipleErrors;
        },

        /**
         * Sets a field as being repeatable, this adds a 'plus' sign after the field
         * thus allowing multiple values to be entered.
         *
         * @method setRepeatable
         * @param fieldId {string} Id of the field the validation is for
         * @param containerId {string} Id of the element representing the
         *        field 'prototype' i.e. the item that will get cloned.
         */
        setRepeatable: function(fieldId, containerId)
        {
            alert("not implemented yet");
        },

        /**
         * Sets whether the submit elements dynamically update
         * their state depending on the current values in the form.
         * The visibility of errors can be controlled via the
         * showErrors parameter.
         *
         * @method setShowSubmitStateDynamically
         * @param showState {boolean} true to have the elements update dynamically
         */
        setShowSubmitStateDynamically: function(showState)
        {
            this.showSubmitStateDynamically = showState;
        },

        /**
         * The forms submit elements are automatically disabled during form submission (and enabled if the form submission fails).
         * Sets this to true if submit elements shall be enabled after a successful form submission as well.
         * Thus making the form "reusable".
         *
         * @param reusable {boolean}
         */
        setAsReusable: function(reusable)
        {
            this.reusable = reusable;
        },

        /**
         * Enables or disables whether the form submits via an AJAX call.
         *
         * @method enableAJAXSubmit
         * @param ajaxSubmit {boolean} true to submit using AJAX, false to submit
         *        using the browser's default behaviour
         * @param callbacks {object} Optional object representing callback handlers
         *        or messages to use, for example
         *        {
         *           successCallback: yourHandlerObject,
         *           failureCallback: yourHandlerObject,
         *           successMessage: yourMessage,
         *           failureMessage: yourMessage
         *        }
         *        Callback handler objects are of the form:
         *        {
         *           fn: function, // The handler to call when the event fires.
         *           obj: object, // An object to pass back to the handler.
         *           scope: object // The object to use for the scope of the handler.
         *        }
         */
        setAJAXSubmit: function(ajaxSubmit, callbacks)
        {
            this.ajaxSubmit = ajaxSubmit;
            this.ajaxSubmitHandlers = callbacks;
        },

        /**
         * Enables or disables submitting the form data in JSON format.
         * Setting the enctype attribute of the form to "application/json"
         * in Firefox will achieve the same result.
         *
         * @method setSubmitAsJSON
         * @param submitAsJSON {boolean} true to submit the form data as JSON,
         *        false to submit one of the standard types "multipart/form-data"
         *        or "application/x-www-form-urlencoded" depending on the enctype
         *        attribute on the form
         */
        setSubmitAsJSON: function(submitAsJSON)
        {
            this.submitAsJSON = submitAsJSON;
        },

        /**
         * Set the http method to use for the AJAX call.
         *
         * @method setAjaxSubmitMethod
         * @param ajaxSubmitMethod {string} the http method to use for the AJAX call
         */
        setAjaxSubmitMethod: function(ajaxSubmitMethod)
        {
            this.ajaxSubmitMethod = ajaxSubmitMethod;
        },

        /**
         * Decides if the browser shall try and reload the current page if a form submission fails due to auth failure.
         *
         * Possible values:
         * true - browser will NOT reload current page
         * false - browser will reload current page
         * null - Will use the default value of noReloadOnAuthFailure in Alfresco.util.Ajax.request
         *
         * @method setAjaxNoReloadOnAuthFailure
         */
        setAjaxNoReloadOnAuthFailure: function(noReloadOnAuthFailure)
        {
            this.ajaxNoReloadOnAuthFailure = noReloadOnAuthFailure;
        },

        /**
         * Adds validation for a specific field on the form.
         * Use the when parameter to define when validation shall be triggered.
         * ALL added validators will be called in the order they were added every time validation is triggered.
         * Validation can also be manually triggered by calling validate().
         *
         * @method addValidation
         * @param fieldId {string} Id of the field the validation is for
         * @param validationHandler {function} Function to call to handle the
         *        actual validation
         * @param validationArgs {object} Optional object representing the
         *        arguments to pass to the validation handler function
         * @param when {string} Name of the event when validation shall be triggered, i.e. "keyup", "blur"
         *        If null, the validation will
         * @param message {string|function|null} Message to be displayed when validation fails,
         *        if a function it will be invoked and shall return a string,
         *        if omitted or null the default message in the handler is used
         * @param config {object|function} Contains advanced instructions for the form, i.e. tooltip behaviour when widgets are used
         * @param config.validationType {string} Set to "mandatory" if a custom mandatory validator is used (rather than Alfresco.forms.mandatory)
         * @param config.errorField {string|HTMLElement} The element that reflects the error (if not provided fieldId will be used)
         */
        addValidation: function(fieldId, validationHandler, validationArgs, when, message, config)
        {
            var field = Dom.get(fieldId);
            if (field == null)
            {
                if (Alfresco.logger.isDebugEnabled())
                    Alfresco.logger.debug("Ignoring validation for field with id of '" + fieldId + "' as it could not be located.");

                return;
            }
            else
            {
                // Make sure every validated element has an id set.
                if (!field.id)
                {
                    Alfresco.util.generateDomId(field, "form-field-")
                }
            }

            if (validationHandler === undefined || validationHandler === null)
            {
                if (Alfresco.logger.isDebugEnabled())
                    Alfresco.logger.debug("Ignoring validation for field with id of '" + fieldId + "' as a validationHandler was not provided.");

                return;
            }

            if (message === undefined)
            {
                message = null;
            }

            // create object representation of validation
            var validation =
            {
                fieldId: field.id,
                args: validationArgs,
                handler: validationHandler,
                message: message,
                originalTitle: field.getAttribute("title") || "",
                event: when,
                config: config
            };

            // add to list of validations
            this.validations.push(validation);

            if (Alfresco.logger.isDebugEnabled())
                Alfresco.logger.debug("Added submit validation for field: " + fieldId +
                    ", using handler: " +
                    (validationHandler.name || YAHOO.lang.dump(validationHandler)) +
                    ", args: " + YAHOO.lang.dump(validationArgs));

            // if an event has been specified attach an event handler
            if (when && when.length > 0)
            {
                // Add blur listener so we can keep track of visited fields and know when to hide error containers
                if (this._fieldEvents[field.id + ":" + "blur"] == this._FIELD_EVENT_UNDEFINED)
                {
                    Event.addListener(field, "blur", this._validationEventFired, field.id, this);
                    this._fieldEvents[field.id + ":" + "blur"] = this._FIELD_EVENT_LISTEN;
                }

                if (this._fieldEvents[field.id + ":" + when] == this._FIELD_EVENT_UNDEFINED)
                {
                    // Add a listener to the field event (unless one already had been added for that event)

                    // YAHOO doesn't seem to process the propertychange via the addListener so we need to take
                    // matters into our own hands. Listening for the "propertychange" event is required so that
                    // the forms runtime can validate when autocomplete is used in IE.
                    if (YAHOO.env.ua.ie > 0 && when == "propertychange")
                    {
                        var _this = this, _fieldId = field.id;
                        field.attachEvent("onpropertychange", function(e) {
                            _this._validationEventFired(e, _fieldId);
                        });
                    }
                    else
                    {
                        Event.addListener(field, when, this._validationEventFired, field.id, this);
                    }
                }
                if (this._fieldEvents[field.id + ":" + when] != this._FIELD_EVENT_VALIDATE)
                {
                    // Now we will validate on the event
                    this._fieldEvents[field.id + ":" + when] = this._FIELD_EVENT_VALIDATE;
                }

                // Add focus listener so we can keep track of visited fields andknow when to show error containers
                if (this._fieldEvents[field.id + ":" + "focus"] == this._FIELD_EVENT_UNDEFINED)
                {
                    Event.addListener(field, "focus", this._validationEventFired, field.id, this);
                    this._fieldEvents[field.id + ":" + "focus"] = this._FIELD_EVENT_LISTEN;
                }

                if (Alfresco.logger.isDebugEnabled())
                    Alfresco.logger.debug("Added field validation for field: " + fieldId +
                        ", using handler: " +
                        (validationHandler.name || YAHOO.lang.dump(validationHandler)) +
                        ", args: " + YAHOO.lang.dump(validationArgs) +
                        ", on event: " + when);
            }
        },

        /**
         * NOTE! Deprecated. The form runtime now handles error displays by itself.
         * Kept to make sure custom validation handlers calling this method won't break.
         *
         * Adds an error to the form.
         *
         * @method addError
         * @param msg {string} The error message to display
         * @param field {object} The element representing the field the error occurred on
         */
        addError: function(msg, field)
        {

        },

        /**
         * Adds the given submitElement to the list of submit elements
         * for the form.
         *
         * @method addSubmitElement
         * @param submitElement Object or string representing the submit element
         */
        addSubmitElement: function(submitElement)
        {
            if (submitElement !== null)
            {
                // add the new element to the list
                this.submitElements.push(submitElement);

                if (this.showSubmitStateDynamically)
                {
                    // force a refresh of the submit state
                    this.validate();
                }
            }
        },

        /**
         * Retrieves the label text for a field
         *
         * @method getFieldLabel
         * @param fieldId {string} The id of the field to get the label for
         * @return {string} The label for the field or the fieldId if a label could not be found
         */
        getFieldLabel: function(fieldId)
        {
            var label = null;

            // lookup the label using the "for" attribute (use the first if multiple found)
            var nodes = Selector.query('label');
            // NOTE: there seems to be a bug in getting label using 'for' or 'htmlFor'
            //       for now get all labels and find the one we want
            if (nodes.length > 0)
            {
                for (var x = 0, xx = nodes.length; x < xx; x++)
                {
                    var elem = nodes[x];
                    if (elem["htmlFor"] == fieldId)
                    {
                        // get the text for the label
                        label = elem.firstChild.nodeValue;
                    }
                }
            }

            // default to the field id if the label element was not found
            if (label == null)
            {
                label = fieldId;
            }

            return label;
        },

        /**
         * Retrieves the data currently held by the form.
         *
         * @method getFormData
         * @return An object representing the form data
         */
        getFormData: function()
        {
            // get the form element
            var form = Dom.get(this.formId);

            // build object representation of the form data
            return this._buildAjaxForSubmit(form);
        },

        /**
         * Applies a Key Listener to input fields to ensure tabbing only targets elements
         * that specifically set a "tabindex" attribute.
         * This has only been seen as an issue with the Firefox web browser, so shouldn't be applied otherwise.
         *
         * @method applyTabFix
         */
        applyTabFix: function()
        {
            if (YAHOO.env.ua.gecko > 0)
            {
                /**
                 * Ensure the Tab key only focusses relevant fields
                 */
                var form = Dom.get(this.formId);

                var fnTabFix = function(id, keyEvent)
                {
                    var event = keyEvent[1];
                    var target = event.target;
                    if (!target.hasAttribute("tabindex"))
                    {
                        Event.stopEvent(event);
                        var el = Selector.query("[tabindex]", form)[0];
                        if (Alfresco.util.isVisible(el))
                        {
                            el.focus();
                        }
                    }
                };

                var tabListener = new KeyListener(form,
                    {
                        keys: KeyListener.KEY.TAB
                    },
                    fnTabFix, "keyup");
                tabListener.enable();
            }
        },

        /**
         * Updates the state of all submit elements.
         *
         * @method updateSubmitElements
         */
        updateSubmitElements: function()
        {
            // To support old forms updating the
            return this.validate(Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD);
        },

        /**
         * Validates all the fields in the form.
         * Updates the state of all submit elements if the "showSubmitStateDynamically" option was set to true.
         *
         * @method validateField
         * @param notificationLevel {Object|null} (Optional) The Event that triggered the validation, shall have a type attribute
         */
        validate: function(notificationLevel)
        {
            notificationLevel = notificationLevel || Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD;
            return this._runValidations({}, false, notificationLevel);
        },

        /**
         * Validates all the fields in the form but indicates it was triggered from a specific event and field.
         * Updates the state of all submit elements if the "showSubmitStateDynamically" option was set to true.
         *
         * @method validateField
         * @param event {Object|null} (Optional) The Event that triggered the validation, shall have a type attribute
         * @param fieldId {String|null} (Optional) The id
         */
        validateField: function(event, fieldId)
        {
            this._validationEventFired(event, fieldId);
        },

        /**
         * Toggles the state of all submit elements.
         *
         * @method _toggleSubmitElements
         * @parameter enabled {boolean} true if the elements shall be enabled
         */
        _toggleSubmitElements: function(enabled)
        {
            // make sure all submit elements show correct state
            for (var x = 0, xx = this.submitElements.length; x < xx; x++)
            {
                var currentItem = this.submitElements[x];
                if (currentItem)
                {
                    if (typeof currentItem == "string")
                    {
                        // get the element with the id and set the disabled attribute
                        Dom.get(currentItem).disabled = !enabled;
                    }
                    else
                    {
                        // TODO: for now if an object is passed presume it's a YUI button
                        currentItem.set("disabled", !enabled);
                    }
                }
            }
        },

        /**
         * Event handler called when a validation event is fired by any registered field.
         *
         * @method _validationEventFired
         * @param event {object} The event
         * @param fieldId {String}
         * @private
         */
        _validationEventFired: function(event, fieldId)
        {
            if (Alfresco.logger.isDebugEnabled())
                Alfresco.logger.debug("Event has been fired for field: " + fieldId);

            if (event)
            {
                if (event.type == "blur")
                {
                    // Mark field as visited when we leave it
                    if (!this._isFieldVisited(fieldId))
                    {
                        this._setFieldAsVisited(fieldId);
                        this._runValidations(event, fieldId, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER);
                    }
                    this._setFieldAsVisited(fieldId);
                    if (this.tooltips[fieldId])
                    {
                        this.hideErrorContainer();
                    }
                }
                else if (event.type == "focus")
                {
                    if (!this.tooltips[fieldId])
                    {
                        this.tooltips[fieldId] = Alfresco.util.createBalloon(this.getFieldValidationEl(fieldId), {
                            effectType: null,
                            effectDuration: 0
                        });
                    }

                    if (YAHOO.util.Dom.hasClass(fieldId, "invalid"))
                    {
                        if (this._fieldEvents[fieldId + ":" + "focus"] != this._FIELD_EVENT_VALIDATE)
                        {
                            // Display error if "focus" event hadn't been added to trigger validation
                            var message = Dom.get(fieldId).getAttribute("title");
                            this.tooltips[fieldId].html(message);
                            this.tooltips[fieldId].show();
                        }
                    }
                }
                else if (event.type == "propertychange" && !Alfresco.util.arrayContains(["value", "checked"], event.propertyName))
                {
                    // "propertychange" events are fired for any attribute change, i.e. "className" & "title",
                    // lets make sure we only validate when necessary
                    return;
                }
            }


            // Ignore tab, shift, enter and escape clicks
            if (!event || (event.keyCode != 9 && event.keyCode != 16 && event.keyCode != 13 && event.keyCode != 27))
            {
                if (event && this._fieldEvents[fieldId + ":" + event.type] == this._FIELD_EVENT_VALIDATE)
                {
                    // Make sure to run the validations anyhow so the tooltips and css error classes are updated & displayed
                    this._runValidations(event, fieldId, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER);
                }
            }
        },

        _errorMessage: function(messTitle, messText)
        {
            Alfresco.util.PopupManager.displayPrompt(
                {
                    title: messTitle,
                    text: messText,
                    buttons: [
                        {
                            text: Alfresco.util.message("Grįžti", this.name),
                            handler: function taskNotSigned_back()
                            {
                                this.destroy();
                            },
                            isDefault: true
                        }]
                });
        },

        _errorTaskNotSignedPrompt: function()
        {
            Alfresco.util.PopupManager.displayPrompt(
                {
                    title: "Užduotis nepasirašyta",
                    text: "Užduoties dokumentas(-ai) nepasirašytas",
                    buttons: [
                        {
                            text: Alfresco.util.message("Grįžti", this.name),
                            handler: function taskNotSigned_back()
                            {
                                this.destroy();
                            },
                            isDefault: true
                        }]
                });
        },
        _errorRegTitlePrompt: function()
        {
            Alfresco.util.PopupManager.displayPrompt(
                {
                    title: "Pranešimo antraštė",
                    text: "Parinkta nenumatyta pranešimo antraštė.",
                    buttons: [
                        {
                            text: Alfresco.util.message("Grįžti", this.name),
                            handler: function regTitle_back()
                            {
                                this.destroy();
                            },
                            isDefault: true
                        }]
                });
        },
        _validatePrompt: function()
        {
            Alfresco.util.PopupManager.displayPrompt(
                {
                    title: "Privalomi laukai",
                    text: "Neužpildyti privalomi duomenų įvedimo laukai.",
                    buttons: [
                        {
                            text: Alfresco.util.message("Grįžti", this.name),
                            handler: function Workflow_back()
                            {
                                this.destroy();
                            },
                            isDefault: true
                        }]
                });
        },

        _validateDatePrompt: function()
        {
            Alfresco.util.PopupManager.displayPrompt(
                {
                    title: "Neteisinga data",
                    text: "Neteisingai parinkta data.",
                    buttons: [
                        {
                            text: Alfresco.util.message("Grįžti", this.name),
                            handler: function Workflow_back()
                            {
                                this.destroy();
                            },
                            isDefault: true
                        }]
                });
        },

        _isDateCorrect: function(dataNuo, dataIki)
        {
            var nuo = dataNuo.val(); nuo = nuo.replace(/\-/g, ''); nuo =  nuo.replace(/\//g, '');
            var iki = dataIki.val();  iki = iki.replace(/\-/g, ''); iki =  iki.replace(/\//g, '');
            if (nuo != "" && iki != ""){
                if (nuo > iki){
                    this._validateDatePrompt();
                    return false;
                }
            } else {}
        },

        _validatePerNotice: function(field1, field2, field3)
        {
            var propArray = new Array('prop_rccwf_perNoticeTekstas', 'prop_rccwf_perNoticeDataNuo', 'prop_rccwf_perNoticeDataIki');
            if (field1 === 1) { if ($("textarea[name="+propArray[0]+"]").val() === ""){this._validatePrompt(); return false;}}
            if (field2 === 1) { if ($("input[name="+propArray[1]+"]").val() === "") {this._validatePrompt(); return false;}}
            if (field3 === 1) { if ($("input[name="+propArray[2]+"]").val() === "") {this._validatePrompt(); return false;}}
        },

        _validatePerAppeal: function(field1, field2, field3, field4)
        {
            var propArray = new Array('prop_rccwf_perAppealPrasymTekstas', 'prop_rccwf_perAppealDataNuo', 'prop_rccwf_perAppealDataIki', 'prop_rccwf_perAppealPridedama');
            if (field1 === 1) { if ($("textarea[name="+propArray[0]+"]").val() === "") {this._validatePrompt(); return false;}}
            if (field2 === 1) { if ($("input[name="+propArray[1]+"]").val() === "") {this._validatePrompt(); return false;}}
            if (field3 === 1) { if ($("input[name="+propArray[2]+"]").val() === "") {this._validatePrompt(); return false;}}
            if (field4 === 1) { if ($("input[name="+propArray[3]+"]").val() === "") {this._validatePrompt(); return false;}}
        },

        _validateFields: function(title,selectedValue)
        {
            if (title === "perNotice") {
                var regTitle = new Array('Dėl darbo poilsio dieną nustatymo','Dėl duomenų pateikimo','Dėl įmonės struktūros pakeitimo','Dėl kasmetinių atostogų atšaukimo','Dėl komandiruotės į užsienį','Dėl materialinės pašalpos skyrimo','Dėl naujo skyriaus įsteigimo','Dėl naujos pareigybės įsteigimo','Dėl papildomo darbo nustatymo','Dėl pareiginio atlyginimo nustatymo','Dėl pareiginio priedo nustatymo','Dėl pareigų pakeitimo','Dėl pavadavimo','Dėl premijavimo','Dėl viršvalandinio darbo nustatymo','Dėl poilsio dienų suteikimo','Dėl darbo drausmės pažeidimo','Dėl papildomų poilsio dienų suteikimo');
                if (selectedValue === regTitle[0]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Dėl darbo poilsio dieną nustatymo
                else if (selectedValue === regTitle[1]) {if(this._validatePerNotice(1,0,1) == false){return false;}} // Dėl duomenų pateikimo
                else if (selectedValue === regTitle[2]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Dėl įmonės struktūros pakeitimo
                else if (selectedValue === regTitle[3]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl kasmetinių atostogų atšaukimo
                else if (selectedValue === regTitle[5]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Dėl materialinės pašalpos skyrimo
                else if (selectedValue === regTitle[6]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl naujo skyriaus įsteigimo
                else if (selectedValue === regTitle[7]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl naujos pareigybės įsteigimo
                else if (selectedValue === regTitle[8]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl papildomo darbo nustatymo
                else if (selectedValue === regTitle[9]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl pareiginio atlyginimo nustatymo
                else if (selectedValue === regTitle[10]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl pareiginio priedo nustatymo
                else if (selectedValue === regTitle[11]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl pareigų pakeitimo
                else if (selectedValue === regTitle[12]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl pavadavimo
                else if (selectedValue === regTitle[13]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Del premijavimo
                else if (selectedValue === regTitle[14]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl viršvalandinio darbo nustatymo
                else if (selectedValue === regTitle[15]) {if(this._validatePerNotice(1,1,0) == false){return false;}} // Dėl poilsio dienų suteikimo
                else if (selectedValue === regTitle[16]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Dėl darbo drausmės pažeidimo
                else if (selectedValue === regTitle[17]) {if(this._validatePerNotice(1,0,0) == false){return false;}} // Dėl papildomų poilsio dienų suteikimo
                else {this._errorRegTitlePrompt();return false;}
            } else {
                var regTitle = new Array('Dėl kasmetinių atostogų suteikimo','Dėl kasmetinių minimalių 35 dienų atostogų suteikimo','Dėl kasmetinių atostogų perkėlimo','Dėl nemokamų atostogų suteikimo','Dėl nemokamų mokymosi atostogų suteikimo','Dėl tėvystės atostogų suteikimo','Dėl nėštumo ir gimdymo atostogų suteikimo','Dėl nėštumo ir gimdymo atostogų pratęsimo','Dėl vaikui prižiūrėti atostogų suteikimo','Dėl materialinės pašalpos skyrimo','Dėl vienkartinės pašalpos gimus vaikui','Dėl poilsio dienų suteikimo','Dėl papildomų poilsio dienų suteikimo','Dėl neatvykimo į darbą administracijos leidimu','Dėl darbo laiko nustatymo','Dėl pavardės pakeitimo įmonės dokumentuose','Dėl atleidimo iš darbo','Dėl vienkartinės pašalpos skyrimo mirus šeimos nariui');
                if (selectedValue === regTitle[0]) {if(this._validatePerAppeal(0,1,1,0) == false){return false;}} // Dėl kasmetinių atostogų suteikimo
                else if (selectedValue === regTitle[1]) {if(this._validatePerAppeal(0,1,0,0) == false){return false;}} // Dėl kasmetinių minimalių 35 dienų atostogų suteikimo
                else if (selectedValue === regTitle[2]) {if(this._validatePerAppeal(1,1,1,0) == false){return false;}} // Dėl kasmetinių atostogų perkėlimo
                else if (selectedValue === regTitle[3]) {if(this._validatePerAppeal(0,1,1,0) == false){return false;}} // Dėl nemokamų atostogų suteikimo
                else if (selectedValue === regTitle[4]) {if(this._validatePerAppeal(1,1,1,1) == false){return false;}} // Dėl nemokamų mokymosi atostogų suteikimo
                else if (selectedValue === regTitle[5]) {if(this._validatePerAppeal(0,1,1,1) == false){return false;}} // Dėl tėvystės atostogų suteikimo
                else if (selectedValue === regTitle[6]) {if(this._validatePerAppeal(0,1,1,0) == false){return false;}} // Dėl nėštumo ir gimdymo atostogų suteikimo
                else if (selectedValue === regTitle[7]) {if(this._validatePerAppeal(0,1,1,0) == false){return false;}} // Dėl nėštumo ir gimdymo atostogų pratęsimo
                else if (selectedValue === regTitle[8]) {if(this._validatePerAppeal(1,1,1,1) == false){return false;}} // Dėl vaikui prižiūrėti atostogų suteikimo
                else if (selectedValue === regTitle[9]) {if(this._validatePerAppeal(1,0,0,1) == false){return false;}} // Dėl materialinės pašalpos skyrimo
                else if (selectedValue === regTitle[10]) {if(this._validatePerAppeal(0,0,0,1) == false){return false;}} // Dėl vienkartinės pašalpos gimus vaikui
                else if (selectedValue === regTitle[11]) {if(this._validatePerAppeal(1,1,0,0) == false){return false;}} // Dėl poilsio dienų suteikimo
                else if (selectedValue === regTitle[12]) {if(this._validatePerAppeal(1,0,0,0) == false){return false;}} // Dėl papildomų poilsio dienų suteikimo
                else if (selectedValue === regTitle[13]) {if(this._validatePerAppeal(0,1,1,0) == false){return false;}} // Dėl neatvykimo į darbą administracijos leidimu
                else if (selectedValue === regTitle[14]) {if(this._validatePerAppeal(1,1,0,0) == false){return false;}} // Dėl darbo laiko nustatymo
                else if (selectedValue === regTitle[15]) {if(this._validatePerAppeal(1,1,0,1) == false){return false;}} // Dėl pavardės pakeitimo įmonės dokumentuose
                else if (selectedValue === regTitle[16]) {if(this._validatePerAppeal(1,1,1,0) == false){return false;}} // Dėl atleidimo iš darbo
                else if (selectedValue === regTitle[17]) {if(this._validatePerAppeal(1,0,0,1) == false){return false;}} // Dėl vienkartinės pašalpos skyrimo mirus šeimos nariui
                else {this._errorRegTitlePrompt(); return false}
            }
        },

        /**
         * Event handler called when the form is submitted.
         *
         * @method _submitInvoked
         * @param event {object} The event
         * @private
         */
        _submitInvoked: function(event)
        {
            // disable submit elements
            this._toggleSubmitElements(false);
            var thisForm = this;

            // get param value from URL
            function getURLParameters(paramName) {
                var sURL = window.document.URL.toString();
                if (sURL.indexOf("?") > 0) {
                    var arrParams = sURL.split("?");
                    var arrURLParams = arrParams[1].split("&");
                    var arrParamNames = new Array(arrURLParams.length);
                    var arrParamValues = new Array(arrURLParams.length);
                    var i = 0;
                    for (i = 0; i < arrURLParams.length; i++) {
                        var sParam =  arrURLParams[i].split("=");
                        arrParamNames[i] = sParam[0];
                        if (sParam[1] != "") {
                            arrParamValues[i] = decodeURIComponent(sParam[1]);
                        } else {
                            arrParamValues[i] = "No Value";
                            return "error";
                        }
                    }
                    for (i = 0; i < arrURLParams.length; i++) {
                        if(arrParamNames[i] == paramName){
                            return arrParamValues[i];
                        }
                    }
                    return "error";
                }
            }

            var validateTaskSigning = function(res) {
                var response = eval('(' + res.serverResponse.responseText + ')');
                var status = response.data.properties.bpm_status;
                if (status) {
                    //console.log("Response is OK");
                    if(status === "Signed") {
                        //console.log("Task is signed");
                        if (document.getElementsByName('prop_rccwf_perNoticeAntraste').length > 0){
                            if (thisForm._validateFields("perNotice", $("select[name=prop_rccwf_perNoticeAntraste]").val()) == false){return false;};
                        } else if (document.getElementsByName('prop_rccwf_perAppealPrasymAntraste').length > 0) {
                            if (thisForm._validateFields("perAppeal", $("select[name=prop_rccwf_perAppealPrasymAntraste]").val()) == false){return false;};
                        } else{}

                        // Datos tikrinimas
                        if ($('input[id*="nuo-cntrl-date"]').length > 0 && $('input[id*="iki-cntrl-date"]').length > 0) {
                            var datan = $('input[id*="nuo-cntrl-date"]');
                            var datai = $('input[id*="iki-cntrl-date"]');
                            if(thisForm._isDateCorrect(datan, datai) == false){return false;}
                        }
                        //serverio adreso reiksmes priskyrimas
                        if (document.getElementsByName('prop_rccwf_serverUrl').length > 0) {
                            $("input[name=prop_rccwf_serverUrl]").val(window.location.host);
                        }
                        //console.log("RETURNED");
                        //return false;

                        if (Alfresco.logger.isDebugEnabled())
                            Alfresco.logger.debug("Submit invoked on formId: ", thisForm.formId);

                        thisForm._setAllFieldsAsVisited();

                        // Run all validators
                        if (thisForm._runValidations(event, null, Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER))
                        {
                            // validation was successful

                            // get the form element
                            var form = Dom.get(thisForm.formId);

                            // call the pre-submit function, passing the form for last-chance processing
                            thisForm.doBeforeFormSubmit.fn.call(thisForm.doBeforeFormSubmit.scope, form, thisForm.doBeforeFormSubmit.obj);

                            // should submission be done using AJAX, or let
                            // the browser do the submit?
                            if (thisForm.ajaxSubmit)
                            {
                                // stop the browser from submitting the form
                                Event.stopEvent(event);

                                // get the form's action URL
                                var submitUrl = form.attributes.action.nodeValue;

                                if (Alfresco.logger.isDebugEnabled())
                                {
                                    Alfresco.logger.debug("Performing AJAX submission to url: ", submitUrl);
                                }

                                // determine how to submit the form, if the enctype
                                // on the form is set to "application/json" then
                                // package the form data as an AJAX string and post
                                if (form.enctype && form.enctype == "multipart/form-data")
                                {
                                    var d = form.ownerDocument;
                                    var iframe = d.createElement("iframe");
                                    iframe.style.display = "none";
                                    Dom.generateId(iframe, "formAjaxSubmit");
                                    iframe.name = iframe.id;
                                    document.body.appendChild(iframe);

                                    // makes it possible to target the frame properly in IE.
                                    window.frames[iframe.name].name = iframe.name;

                                    form.target = iframe.name;
                                    form.submit();
                                    return;
                                }
                                else
                                {
                                    // Only disable submit elements for XMLHttpRequests since we then have a chance of enabling them on failure
                                    thisForm._toggleSubmitElements(false);
                                }

                                // create config object to pass to request helper
                                var config =
                                {
                                    method: thisForm.ajaxSubmitMethod,
                                    url: submitUrl
                                };

                                if (thisForm.ajaxSubmitHandlers)
                                {
                                    thisForm.ajaxSubmitHandlers = thisForm.ajaxSubmitHandlers || {};
                                    config.successMessage = thisForm.ajaxSubmitHandlers.successMessage;
                                    config.successCallback = {
                                        fn: function(response, successCallback)
                                        {
                                            if (Dom.get(thisForm.formId))
                                            {
                                                // The form still exists
                                                thisForm._resetAllVisitedFields();
                                                if (thisForm.reusable)
                                                {
                                                    if (thisForm.showSubmitStateDynamically)
                                                    {
                                                        // Update using validation
                                                        thisForm.updateSubmitElements();
                                                    }
                                                    else
                                                    {
                                                        // Enable submit buttons
                                                        thisForm._toggleSubmitElements(true);
                                                    }
                                                }
                                            }
                                            if (successCallback.fn)
                                            {
                                                successCallback.fn.call(successCallback.scope || thisForm, response, successCallback.obj);
                                            }
                                        },
                                        obj: thisForm.ajaxSubmitHandlers.successCallback || {},
                                        scope: thisForm
                                    };
                                    config.failureMessage = thisForm.ajaxSubmitHandlers.failureMessage;
                                    config.failureCallback = {
                                        fn: function(response, failureCallback)
                                        {
                                            if (Dom.get(thisForm.formId))
                                            {
                                                // The form still exists
                                                thisForm._resetAllVisitedFields();
                                                if (thisForm.showSubmitStateDynamically)
                                                {
                                                    // Update using validation
                                                    thisForm.updateSubmitElements();
                                                }
                                                else
                                                {
                                                    // Enable submit buttons
                                                    thisForm._toggleSubmitElements(true);
                                                }
                                            }
                                            if (failureCallback.fn)
                                            {
                                                failureCallback.fn.call(failureCallback.scope || thisForm, response, failureCallback.obj);
                                            }
                                        },
                                        obj: thisForm.ajaxSubmitHandlers.failureCallback || {},
                                        scope: thisForm
                                    };
                                }
                                if (thisForm.submitAsJSON)
                                {
                                    var jsonData = thisForm._buildAjaxForSubmit(form);

                                    // set up specific config
                                    config.dataObj = jsonData;
                                    config.noReloadOnAuthFailure = thisForm.ajaxNoReloadOnAuthFailure;

                                    // call the pre-request function, passing the config object for last-chance processing
                                    if (thisForm.doBeforeAjaxRequest.fn.call(thisForm.doBeforeAjaxRequest.scope, config, thisForm.doBeforeAjaxRequest.obj))
                                    {
                                        if (Alfresco.logger.isDebugEnabled())
                                            Alfresco.logger.debug("Submitting JSON data: ", config.dataObj);

                                        Alfresco.util.Ajax.jsonRequest(config);
                                    }
                                    else
                                    {
                                        if (Alfresco.logger.isDebugEnabled())
                                            Alfresco.logger.debug("JSON data request cancelled in doBeforeAjaxRequest()");
                                    }
                                }
                                else
                                {
                                    if (Alfresco.logger.isDebugEnabled())
                                        Alfresco.logger.debug("Submitting data in form: ", form.enctype);

                                    // set up specific config
                                    config.dataForm = form;
                                    Alfresco.util.Ajax.request(config);
                                }
                            }
                        }
                        else
                        {
                            // stop the event from continuing and sending the form.
                            Event.stopEvent(event);

                            if (Alfresco.logger.isDebugEnabled())
                                Alfresco.logger.debug("Submission prevented as validation failed");
                        }
                    } else {
                        //console.log("Task is not signed");
                        thisForm._errorTaskNotSignedPrompt();
                        // enable submit elements
                        thisForm._toggleSubmitElements(true);
                    }
                } else {
                    //console.log("Response is BAD");
                    thisForm.errorMessage("Klaida tikrinant užduoties pasirašymą.");
                    // enable submit elements
                    thisForm._toggleSubmitElements(true);
                }
            };

            function validateSigning(){
                var task = null;
                taskId = getURLParameters("taskId");
                if (taskId != "error"){
                    Alfresco.util.Ajax.jsonGet({
                        url : Alfresco.constants.PROXY_URI + "api/task-instances/"+encodeURIComponent(taskId),
                        successCallback : {
                            fn : validateTaskSigning,
                            scope : this
                        },
                        failureCallback : {
                            fn : function() {},
                            scope : this
                        }
                    });
                }
            }
            validateSigning();
        },

        /**
         * Builds a JSON representation of the current form
         *
         * @method _buildAjaxForSubmit
         * @param form {object} The form object to build the JSON for
         * @private
         */
        _buildAjaxForSubmit: function(form)
        {
            if (form !== null)
            {
                var formData = {},
                    length = form.elements.length;

                for (var i = 0; i < length; i++)
                {
                    var element = form.elements[i],
                        name = element.name;

                    if (name == "-" || element.disabled || element.type === "button")
                    {
                        continue;
                    }
                    if (name == undefined || name == "")
                    {
                        name = element.id;
                    }
                    var value = (element.type === "textarea") ? element.value : YAHOO.lang.trim(element.value);
                    if (name)
                    {
                        // check whether the input element is an array value
                        if ((name.length > 2) && (name.substring(name.length - 2) == '[]'))
                        {
                            name = name.substring(0, name.length - 2);
                            if (formData[name] === undefined)
                            {
                                formData[name] = new Array();
                            }
                            formData[name].push(value);
                        }
                        // check whether the input element is an object literal value
                        else if (name.indexOf(".") > 0)
                        {
                            var names = name.split(".");
                            var obj = formData;
                            var index;
                            for (var j = 0, k = names.length - 1; j < k; j++)
                            {
                                index = names[j];
                                if (obj[index] === undefined)
                                {
                                    obj[index] = {};
                                }
                                obj = obj[index];
                            }
                            obj[names[j]] = value;
                        }
                        else if (!((element.type === "checkbox" || element.type === "radio") && !element.checked))
                        {
                            if (element.type == "select-multiple")
                            {
                                for (var j = 0, jj = element.options.length; j < jj; j++)
                                {
                                    if (element.options[j].selected)
                                    {
                                        if (formData[name] == undefined)
                                        {
                                            formData[name] = new Array();
                                        }
                                        formData[name].push(element.options[j].value);
                                    }
                                }
                            }
                            else
                            {
                                formData[name] = value;
                            }
                        }
                    }
                }

                return formData;
            }
        },

        /**
         * Checks if a field has been visited
         *
         * @function _isFieldVisited
         * @param fieldId THe fieldId to mark as edited
         * @return {boolean} true of the field has been edited (or the user has tried to submit the form)
         */
        _isFieldVisited: function(fieldId)
        {
            return (YAHOO.lang.isBoolean(this._visitedFields) && this._visitedFields) ||
                (YAHOO.lang.isObject(this._visitedFields) && this._visitedFields[fieldId]);
        },

        /**
         * Marks a field as visited
         *
         * @function _setFieldAsVisited
         * @param fieldId {string}
         */
        _setFieldAsVisited: function(fieldId)
        {
            if (!YAHOO.lang.isBoolean(this._visitedFields) && YAHOO.lang.isObject(this._visitedFields))
            {
                return this._visitedFields[fieldId] = true;
            }
        },

        /**
         * Marks all fields as visited
         *
         * @function _setAllFieldsEdited
         */
        _setAllFieldsAsVisited: function()
        {
            this._visitedFields = true;
        },

        _resetAllVisitedFields: function()
        {
            this._visitedFields = {};
        },


        _getConfig: function(config, configName, defaultValue)
        {
            var c = config || {};
            if (YAHOO.lang.isFunction(config))
            {
                c = config();
            }
            var result = Alfresco.util.findValueByDotNotation(c, configName);
            return (result != undefined || result != null) ? result : defaultValue;
        },

        _isMandatoryValidator: function(val)
        {
            return val.handler == Alfresco.forms.validation.mandatory || (this._getConfig(val.config, "validationType", "invalid") == "mandatory");
        },

        /**
         * Executes all registered validations and returns result.
         *
         * @method _runValidations
         * @parameter event {Object|null} The event that triggered the validation OR null if validation was programmatically called
         * @parameter fieldId {string|null|boolean} The current el that triggered the event OR null if validation was programmatically called
         * @private
         */
        _runValidations: function(event, fieldId, notificationLevel)
        {
            var allErrors = [],
                errorsByField = {},
                allWarnings = [],
                warningsByField = {},
                fieldMsg,
                message,
                validationType,
                MANDATORY = "mandatory",
                INVALID = "invalid",
                field,
                valFieldId,
                val,
                suppressValidationNotification,
                primaryErrorFieldId = null;

            // Iterate through all validations (for all enabled fields) so we can tell if the complete form is valid or not
            for (var x = 0, xx = this.validations.length; x < xx; x++)
            {
                val = this.validations[x];

                field = Dom.get(val.fieldId);
                if (field !== null && !field.disabled)
                {
                    valFieldId = field.getAttribute("id");
                    errorsByField[valFieldId] = errorsByField[valFieldId] || [];
                    warningsByField[valFieldId] = warningsByField[valFieldId] || [];

                    // Make sure invalid fields are showed as mandatory until the user has had a chance of changing the value
                    validationType = this._isMandatoryValidator(val) && !this._isFieldVisited(valFieldId) ? MANDATORY : INVALID;
                    if (val.message)
                    {
                        message = val.message;
                        if (YAHOO.lang.isFunction(val.message))
                        {
                            // Validator wanted to create error message manually
                            message = val.message.call(this, val.args);
                        }
                        if (message)
                        {
                            // Make sure message parameters based on validator args are resolved
                            message = YAHOO.lang.substitute(message, val.args);
                        }
                    }
                    else
                    {
                        // Message is missing, use these as a last resort
                        var key;
                        if (this._isMandatoryValidator(val))
                        {
                            key = "Alfresco.forms.validation.mandatory.message";
                        }
                        else
                        {
                            key = "Alfresco.forms.validation.invalid.message";
                        }
                        message = Alfresco.util.message(key);
                    }

                    // Make sure that validation notifications aren't triggered by events from other validations for the same field
                    suppressValidationNotification = (validationType == INVALID) &&
                        (event != null && event.type != "blur" && event.type != val.event && event.keyCode != 13) &&
                        (fieldId == valFieldId);

                    if (!val.handler(field, val.args, null, this, true, message))
                    {
                        // The field is invalid

                        // Lets see if the validator wants to use another Dom id as context for the error container.
                        var errorField = Dom.get(this._getConfig(val.config, "errorField", field));
                        if (!errorField.id)
                        {
                            // All fields must have a dom id
                            Alfresco.util.generateDomId(errorField);
                        }
                        if (errorField.id != fieldId && validationType == INVALID)
                        {
                            // Make sure that error containers are created for custom fields as well
                            errorsByField[errorField.id] = errorsByField[errorField.id] || [];
                            errorsByField[errorField.id].push(message);
                        }

                        // Mark the first field with an error as the primary field (will be used if user tried to submit form)
                        if (primaryErrorFieldId == null)
                        {
                            primaryErrorFieldId = errorField.id;
                        }

                        if (suppressValidationNotification)
                        {
                            // There was a validation error for this field but it was configured to get displayed on another event
                            continue;
                        }

                        // Prepare error message including field name (the label in the dom)
                        fieldMsg = YAHOO.lang.trim(this.getFieldLabel(valFieldId)) || "";
                        if (fieldMsg.length > 0)
                        {
                            if (fieldMsg.indexOf(":") < 0)
                            {
                                fieldMsg += ":";
                            }
                            fieldMsg += " ";
                        }
                        fieldMsg += message;

                        // Update error indication css classes
                        if (validationType == INVALID)
                        {
                            // Remove the mandatory class since it now is invalid
                            if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD)
                            {
                                YAHOO.util.Dom.removeClass(field, MANDATORY);
                                if (field == errorField)
                                {
                                    YAHOO.util.Dom.addClass(field, INVALID);
                                }
                                else
                                {
                                    YAHOO.util.Dom.removeClass(field, INVALID);
                                }

                                // Update message
                                field.setAttribute("title", message);
                            }
                            allErrors.push({ id: valFieldId, msg: fieldMsg });
                            errorsByField[valFieldId].push(message);
                        }
                        else
                        {
                            // Actual errors have higher priority than a "mandatory error"
                            if (errorsByField[valFieldId].length == 0)
                            {
                                if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD)
                                {
                                    YAHOO.util.Dom.removeClass(field, INVALID);
                                    if (field == errorField)
                                    {
                                        YAHOO.util.Dom.addClass(field, MANDATORY);
                                    }
                                    else
                                    {
                                        YAHOO.util.Dom.removeClass(field, INVALID);
                                    }
                                    field.setAttribute("title", message);
                                }
                            }
                            warningsByField[valFieldId].push(message);
                            allWarnings.push({ id: valFieldId, msg: fieldMsg });
                        }

                        YAHOO.Bubbling.fire("formValidationError", {
                            msg: fieldMsg,
                            field: field,
                            type: validationType
                        });
                    }
                    else
                    {
                        if (suppressValidationNotification)
                        {
                            // There was a validation error, but it was configured to be displayed on another event
                            continue;
                        }

                        if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_FIELD)
                        {

                            if (errorsByField[valFieldId].length == 0)
                            {
                                YAHOO.util.Dom.removeClass(field, INVALID);
                            }
                            if (warningsByField[valFieldId].length == 0)
                            {
                                YAHOO.util.Dom.removeClass(field, MANDATORY);
                            }
                            if (errorsByField[valFieldId].length == 0 && warningsByField[valFieldId].length == 0)
                            {
                                field.setAttribute("title", val.originalTitle);
                                if (this.tooltips[valFieldId])
                                {
                                    this.tooltips[valFieldId].html("");
                                    this.tooltips[valFieldId].hide();
                                }
                            }
                        }
                    }
                }
            }

            // Use focused field as context for the error container ...
            var errorFieldId = document.activeElement.id || null;
            if (notificationLevel >= Alfresco.forms.Form.NOTIFICATION_LEVEL_CONTAINER)
            {

                if ((event == null || event.type == "submit") && primaryErrorFieldId &&
                    (!warningsByField[errorFieldId] || warningsByField[errorFieldId].length == 0) &&
                    (!errorsByField[errorFieldId] || errorsByField[errorFieldId].length == 0))
                {
                    // ... unless the user tried to submit the form, then use the forst field with an error
                    errorFieldId = primaryErrorFieldId;
                    var el = this.getFieldValidationEl(Dom.get(errorFieldId));
                    if (Alfresco.util.isVisible(el))
                    {
                        if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 9)
                        {
                            // No action - this causes a script error on IE8 and below.
                        }
                        else if (YAHOO.lang.isFunction(el.focus))
                        {
                            el.focus();
                        }
                    }
                }

                if (this.errorContainer !== null && errorFieldId && errorsByField[errorFieldId])
                {
                    if (this.errorContainer === "tooltip")
                    {
                        /*
                         for (var key in this.tooltips)
                         {
                         if (this.tooltips.hasOwnProperty(key) && key != errorFieldId)
                         {
                         this.tooltips[key].hide();
                         }
                         }
                         */
                        if (errorsByField[errorFieldId].length > 0)
                        {
                            if (!this.tooltips[errorFieldId])
                            {
                                this.tooltips[errorFieldId] = Alfresco.util.createBalloon(this.getFieldValidationEl(errorFieldId), {
                                    effectType: null,
                                    effectDuration: 0
                                });
                            }

                            var html = '';
                            for (var i = 0; i < errorsByField[errorFieldId].length; i++)
                            {
                                if (i > 0 && !this.showMultipleErrors)
                                {
                                    break;
                                }
                                html += '<div>' + Alfresco.util.encodeHTML(errorsByField[errorFieldId][i]) + '</div>';
                            }
                            this.tooltips[errorFieldId].html(html);
                            this.tooltips[errorFieldId].show();
                        }
                        else if (this.tooltips[errorFieldId])
                        {
                            this.tooltips[errorFieldId].html("");
                            this.tooltips[errorFieldId].hide();
                        }
                    }
                    else if (this.errorContainer === "alert" && allErrors.length > 0)
                    {
                        var msg = '';
                        for (var i = 0; i < allErrors.length; i++)
                        {
                            if (i > 0 && !this.showMultipleErrors)
                            {
                                break;
                            }
                            msg += allErrors[i] + '\n';
                        }
                        alert(msg);
                    }
                    else if (YAHOO.lang.isString(this.errorContainer))
                    {
                        var htmlNode = Dom.get(this.errorContainer);
                        if (htmlNode !== null)
                        {
                            var html = '';
                            for (var i = 0; i < allErrors.length; i++)
                            {
                                if (i > 0 && !this.showMultipleErrors)
                                {
                                    break;
                                }
                                html += '<div><label for="' + allErrors[i].id + '">' + Alfresco.util.encodeHTML(allErrors[i].msg) + '</label></div>';
                            }
                            htmlNode.style.display = "block";
                            htmlNode.innerHTML = html;
                        }
                    }
                }
            }

            this._valid = primaryErrorFieldId == null;

            // update submit elements state, if required
            if (this.showSubmitStateDynamically)
            {
                this._toggleSubmitElements(this._valid);
            }

            return this._valid;
        },

        getFieldValidationEl: function(fieldId)
        {
            var el = Dom.get(fieldId);
            if ((el.tagName.toLowerCase() == "input" && el.type == "hidden") || !Alfresco.util.isVisible(el))
            {
                return el.parentNode;
            }
            return el;
        },

        hideErrorContainer: function()
        {
            if (this.errorContainer === "tooltip")
            {
                for (var key in this.tooltips)
                {
                    if (this.tooltips.hasOwnProperty(key))
                    {
                        this.tooltips[key].hide();
                    }
                }
            }
            else if (this.errorContainer === "alert")
            {
                // Not applicable
            }
            else if (YAHOO.lang.isString(this.errorContainer))
            {
                // todo Filter out errors for the field
            }
        },

        /**
         * Displays an internal form error message.
         *
         * @method _showInternalError
         * @param msg {string} The error message to display
         * @param field {object} The element representing the field the error occurred on
         * @private
         */
        _showInternalError: function(msg, field)
        {
            this.addError("Internal Form Error: " + msg, field);
        },

        reset: function()
        {
            this._resetAllVisitedFields();
            Dom.get(this.formId).reset();
            this.validate();
        }
    };
})();

(function()
{

    /**
     * Mandatory validation handler, tests that the given field has a value.
     *
     * @method mandatory
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.mandatory = function mandatory(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating mandatory state of field '" + field.id + "'");

        var valid = true;

        if (field.type && field.type == "radio")
        {
            //       wouldn't a radio button normally have a default
            //       'checked' option?

            var formElem = Dom.get(form.formId),
                radios = formElem[field.name],
                anyChecked = false;
            for (var x = 0, xx = radios.length; x < xx; x++)
            {
                if (radios[x].checked)
                {
                    anyChecked = true;
                    break;
                }

            }

            valid = anyChecked;
        }
        else if (field.type && field.type == "checkbox")
        {
            valid = field.checked;
        }
        else
        {
            valid = YAHOO.lang.trim(field.value).length !== 0;
        }

        return valid;
    };


    /**
     * Password match validation handler, tests that the given field's value matches another password field.
     *
     * @method passwordMatch
     * @param field {object} The element representing the field the validation is for
     * @param args {object}
     * @param args.el {HTMLElement|String} The input element that contains the element to coimpare against.
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.passwordMatch = function passwordMatch(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating password match of field '" + field.id + "' using args: " + YAHOO.lang.dump(args));
        if (YAHOO.lang.trim(field.value).length == 0)
        {
            return true;
        }

        var valid = false;
        var myArgs = YAHOO.lang.merge(
            {
                el: null
            }, args);

        if (myArgs.el)
        {
            var el = YAHOO.util.Dom.get(myArgs.el);
            if (el.value == field.value)
            {
                valid = true;
            }
        }

        return valid;
    };

    /**
     * Length validation handler, tests that the given field's value has either
     * a minimum and/or maximum length.
     *
     * @method length
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Object representing the minimum and maximum length, and whether to crop content
     *        {
     *           min: 3,
     *           max: 10,
     *           crop: true
     *        }
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.length = function length(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating length of field '" + field.id +
                "' using args: " + YAHOO.lang.dump(args));
        if (YAHOO.lang.trim(field.value).length == 0)
        {
            return true;
        }

        var valid = true;
        var myArgs = YAHOO.lang.merge(
            {
                min: -1,
                max: -1,
                crop: false,
                includeWhitespace: true
            }, args);

        if (myArgs.minLength)
        {
            myArgs.min = myArgs.minLength;
        }

        if (myArgs.maxLength)
        {
            myArgs.max = myArgs.maxLength;
        }

        var length = myArgs.includeWhitespace ? field.value.length : YAHOO.lang.trim(field.value).length;

        if (myArgs.min != -1 && length < myArgs.min)
        {
            valid = false;
        }

        if (myArgs.max != -1 && length > myArgs.max)
        {
            valid = false;
            if (myArgs.crop)
            {
                if (myArgs.includeWhitespace)
                {
                    field.value = YAHOO.lang.trim(field.value);
                }
                if (field.value.length > myArgs.max)
                {
                    field.value = field.value.substring(0, myArgs.max);
                }
                if (field.type && field.type == "textarea")
                {
                    field.scrollTop = field.scrollHeight;
                }
                valid = true;
            }
        }

        return valid;
    };

    /**
     * Number validation handler, tests that the given field's value is a number.
     *
     * @method number
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Optional object containing a "repeating" flag
     *        {
     *           repeating: true
     *        }
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.number = function number(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a number");

        var repeating = false;

        // determine if field has repeating values
        if (args !== null && args.repeating)
        {
            repeating = true;
        }

        var valid = true;
        if (repeating)
        {
            // as it's repeating there could be multiple comma separated values
            var values = field.value.split(",");
            for (var i = 0; i < values.length; i++)
            {
                valid = (isNaN(values[i]) == false);

                if (!valid)
                {
                    // stop as soon as we find an invalid value
                    break;
                }
            }
        }
        else
        {
            valid = (isNaN(field.value) == false);
        }

        return valid;
    };

    /**
     * Number range validation handler, tests that the given field's value has either
     * a minimum and/or maximum value.
     *
     * @method numberRange
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Object representing the minimum and maximum value, for example
     *        {
     *           min: 18;
     *           max: 30;
     *        }
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.numberRange = function numberRange(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating number range of field '" + field.id +
                "' using args: " + YAHOO.lang.dump(args));

        var valid = true;
        var value = field.value.toString();

        if (value.length > 0)
        {
            if (isNaN(value))
            {
                valid = false;
            }
            else
            {
                var min = -1;
                var max = -1;

                if (args.min)
                {
                    min = parseInt(args.min);
                }

                if (args.minValue)
                {
                    min = parseInt(args.minValue);
                }

                if (args.max)
                {
                    max = parseInt(args.max);
                }

                if (args.maxValue)
                {
                    max = parseInt(args.maxValue);
                }

                if (min != -1 && value < min)
                {
                    valid = false;
                }

                if (max != -1 && value > max)
                {
                    valid = false;
                }
            }
        }

        return valid;
    };

    /**
     * Node name validation handler, tests that the given field's value is a valid
     * name for a node in the repository.
     *
     * @method nodeName
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.nodeName = function nodeName(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid node name");

        if (!args)
        {
            args = {};
        }

        /**
         * Pattern for disallowing leading and trailing spaces. See CHK-6614
         * args.pattern = /([\"\*\\\>\<\?\/\:\|]+)|([\.]?[\.]+$)|(^[ \t]+|[ \t]+$)/;
         */
        args.pattern = /([\"\*\\\>\<\?\/\:\|]+)|([\.]?[\.]+$)/;
        args.match = false;

        return Alfresco.forms.validation.regexMatch(field, args, event, form);
    };

    /**
     * Wiki page title validation handler, tests that the given field's value is a valid
     * name for a node in the repository.
     *
     * @method nodeName
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @param silent {boolean} Determines whether the user should be informed upon failure
     * @param message {string} Message to display when validation fails, maybe null
     * @static
     */
    Alfresco.forms.validation.wikiTitle = function wikiTitle(field, args, event, form, silent, message)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid node name");

        if (!args)
        {
            args = {};
        }

        args.pattern = /([\\\?\/\|]+)|([\.]?[\.]+$)/;
        args.match = false;

        return Alfresco.forms.validation.regexMatch(field, args, event, form, silent, message);
    };

    /**
     * NodeRef validation handler, tests that the given field's value is a valid
     * nodeRef identifier for a node in the repository.
     *
     * @method nodeRef
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.nodeRef = function nodeRef(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid noderef");

        if (!args)
        {
            args = {};
        }

        args.pattern = /^[^\:^ ]+\:\/\/[^\:^ ]+\/[^ ]+$/;

        return Alfresco.forms.validation.regexMatch(field, args, event, form);
    };


    /**
     * Email validation handler, tests that the given field's value is a valid
     * email address.
     *
     * @method email
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.email = function email(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid email address");

        if (!args)
        {
            args = {};
        }

        args.pattern = /^[^\(^\)^\{^\}^'^"^,^:^;^<^>^\\^\[^\]^\s^\@]+@[^\(^\)^\{^\}^'^"^,^:^;^<^>^\\^\[^\]^\s^\@]+\.[A-Za-z]{2,7}$/;
        args.match = true;

        return Alfresco.forms.validation.regexMatch(field, args, event, form);
    };


    /**
     * Time validation handler, tests that the given field's value is a valid time value.
     *
     * @method time
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.time = function time(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid time value");

        if (!args)
        {
            args = {};
        }

        args.pattern = /^([0-1]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/;
        args.match = true;

        return Alfresco.forms.validation.regexMatch(field, args, event, form);
    };

    /**
     * URL validation handler, tests that the given field's value is a valid URL
     *
     * @method url
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.url = function url(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' is a valid URL");

        var expression = /(ftp|http|https):\/\/[\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/,
            valid = true;

        if (field.value.length > 0)
        {
            // Check an empty string replacement returns an empty string
            var pattern = new RegExp(expression);
            valid = field.value.replace(pattern, "") === "";
        }

        return valid;
    };


    /**
     * Regular expression validation handler, tests that the given field's value matches
     * the supplied regular expression.
     *
     * @method regexMatch
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Object representing the expression.
     * The args object should have the form of:
     * {
     *    pattern: {regexp}, // A regular expression
     *    match: {boolean}   // set to false if the regexp should NOT match the input, default is true
     * }
     * An example to validate a field represents an email address can look like:
     * {
     *    pattern: /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/
     * }
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.regexMatch = function regexMatch(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating regular expression of field '" + field.id +
                "' using args: " + YAHOO.lang.dump(args));
        var valid = true;

        if (field.value && field.value.length > 0)
        {
            // The pattern SHOULD match by default
            if (args.match === undefined)
            {
                args.match = true;
            }

            // Check if the patterns match
            var pattern = new RegExp(args.pattern);
            valid = pattern.test(field.value);

            // Adjust the result if the test wasn't intended to match
            if (!args.match)
            {
                valid = !valid;
            }
        }

        return valid;
    };


    /**
     * Repository regular expression handler, simply used as a pass through to the
     * standard regexMatch handler after converting the paramater names.
     *
     * @method repoRegexMatch
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.repoRegexMatch = function repoRegexMatch(field, args, event, form)
    {
        // convert parameters
        args.pattern = args.expression;
        args.match = args.requiresMatch;

        // call the standard regex handler
        return Alfresco.forms.validation.regexMatch(field, args, event, form);
    };

    /**
     * Validation handler for a valid date and time, currently this simply looks for the
     * presence of the 'invalid' class applied to the relevant field. This implies that this
     * validation handler must be added after any other handlers that determine validity.
     *
     * @method validDateTime
     * @param field {object} The element representing the field the validation is for
     * @param args {object} Not used
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.validDateTime = function validDateTime(field, args, event, form)
    {
        if (Alfresco.logger.isDebugEnabled())
            Alfresco.logger.debug("Validating field '" + field.id + "' has a valid date and time");

        return !YAHOO.util.Dom.hasClass(field, "invalid");
    };

    /**
     * Validation handler for the repository 'list of values' constraint. As the UI
     * handles this by displaying the list of allowable values this handler is a dummy
     * placeholder.
     *
     * @method listOfValues
     * @param field {object} The element representing the field the validation is for
     * @param args {object} The list of allowable values
     * @param event {object} The event that caused this handler to be called, maybe null
     * @param form {object} The forms runtime class instance the field is being managed by
     * @static
     */
    Alfresco.forms.validation.inList = function inList(field, args, event, form)
    {
        return true;
    };

})();